package fr.miage.orleans.aar.consultation;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import fr.miage.orleans.aar.ejb.FacadeBean;
import fr.miage.orleans.aar.ejb.peupler.FacadePeuplerBean;
import fr.miage.orleans.aar.modele.Joueur;
import fr.miage.orleans.aar.modele.PosteJoueur;
import fr.miage.orleans.aar.modele.Tournoi;
import fr.miage.orleans.aar.modele.utils.Peupler;
import fr.miage.orleans.aar.modele.valueobject.ValueObjectEquipeDetail;
import fr.miage.orleans.aar.modele.valueobject.ValueObjectMatch;
import fr.miage.orleans.aar.modele.valueobject.ValueObjectTournoi;
import fr.miage.orleans.aar.utils.Md5;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.ejb.EJB;
import javax.servlet.annotation.WebServlet;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import fr.miage.orleans.aar.ejb.FacadeGettersBean;
import fr.miage.orleans.aar.ejb.FacadeGettersVoBean;

/**
 *
 * @author Steve Cancès <steve.cances@gmail.com>
 */
@WebServlet(urlPatterns = "/consultation", asyncSupported = true)
public class ConsultationServlet extends HttpServlet {

	/**
	 *
	 */
	private static final long serialVersionUID = -8318895986040706491L;
	/**
	 * Les strings
	 */
	private static final String STRING_ACTION = "action";
	private static final String STRING_WEBINF = "/WEB-INF/";

	/**
	 * Les actions
	 */
	private static final String ACTION_DETAIL_TOURNOI = "detailTournoi";
	private static final String ACTION_PEUPLER = "peupler";
	private static final String ACTION_RAZBDD = "razbdd";
	private static final String ACTION_ADMIN = "admin";
	private static final String ACTION_INSCRIPTION = "inscription";
	private static final String ACTION_DETAIL_EQUIPE = "detailEquipe";
	private static final String ACTION_REFRESH_MATCH = "refreshMatch";
	private static final String ACTION_REFRESH_MATCH_POL = "refreshMatchPol";
	private static final String ACTION_GET_TOURNOI_JSON = "getTournoi";


	private static final int timer = 32000;
	/**
	 * Les JSPs
	 */
	private static final String JSP_INDEX = "/index.jsp";
	private static final String JSP_CONSULTATION = "/WEB-INF/consultation.jsp";
	private static final String JSP_DETAIL_TOURNOI = "WEB-INF/consultation_detail_tournoi.jsp";
	private static final String JSP_INSCRIPTION = "/WEB-INF/inscriptiontournoi.jsp";
	private static final String JSP_DETAIL_EQUIPE = "WEB-INF/consultation_detail_equipe.jsp";

	private static final String SERVLET_INSCRIPTION = "inscription";
	/**
	 * Les attributs de session
	 */
	private static final String SA_TOURNOIS = "tournois";
	private static final String SA_EQUIPES = "equipes";
	private static final String SA_DETAIL_EQUIPE = "detail_equipe";
	private static final String SA_VOTOURNOI = "votournoi";
	private static final String SA_MATCHJSON = "JSONMatchs";
	private static final String SA_POSTEJOUEUR  = "posteJoueur";
	private static final String SA_VOTOURNOIHASH  = "posteJoueur";


	@EJB
	private FacadeBean facade;

	@EJB
	private FacadeGettersBean facadeGetters;

	@EJB
	private FacadeGettersVoBean facadeGettersVo;

	@EJB
	private FacadePeuplerBean facadePeupler;

	/**
	 * Processes requests for both HTTP <code>GET</code> and <code>POST</code>
	 * methods.
	 *
	 * @param request servlet request
	 * @param response servlet response
	 * @throws ServletException if a servlet-specific error occurs
	 * @throws IOException if an I/O error occurs
	 */
	protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html;charset=UTF-8");

		Peupler.creerPostes(this.facadePeupler);
		Peupler.creerAdmin(this.facadePeupler, "Exbrayat", "Matthieu", "admin", "admin");
		Peupler.creerArbitres(this.facadePeupler);

		String action = request.getParameter(STRING_ACTION);
		if (action == null || action.isEmpty()) {
			this.processIndex(request, response);
		} else {
			switch (action) {
			case ACTION_DETAIL_TOURNOI: {
				this.processDetailTournoi(request, response);
				break;
			}
			case ACTION_PEUPLER: {
				this.processPeupler(request, response);
				break;
			}
			case ACTION_RAZBDD: {
				this.processRazBdd(request, response);
				break;
			}
			case ACTION_INSCRIPTION: {
				this.processInscriptionTournoi(request, response);
				break;
			}
			case ACTION_DETAIL_EQUIPE: {
				this.processDetailEquipe(request, response);
				break;
			}
			case ACTION_REFRESH_MATCH : 
			{
				this.processRefreshMatch(request, response);
				break;
			}
			case ACTION_REFRESH_MATCH_POL : 
			{
				try
				{
					this.processLongRefreshMatch(request, response);
				}
				catch(Exception e)
				{
					e.printStackTrace();
					this.processIndex(request, response);
				}

				break;
			}
			case ACTION_GET_TOURNOI_JSON : 
			{
				try
				{
					this.processGetTournoiJSON(request, response);
				}
				catch(Exception e)
				{
					e.printStackTrace();
					this.processIndex(request, response);
				}
				break;
			}
			default: {
				this.processIndex(request, response);
			}
			}
		}
	}

	private void processRefreshMatch(HttpServletRequest request,
			HttpServletResponse response) throws IOException {
		String idMatch = request.getParameter("idmatch");

		ValueObjectMatch vom = facadeGettersVo.getVOMatch(Integer.parseInt(idMatch));
		response.setContentType("application/json");
		PrintWriter out = response.getWriter();
		Gson gson = new Gson();
		String newhash = Md5.encode(gson.toJson(vom));
		Returnvalue returnvalue = new Returnvalue(newhash, vom);
		out.print(gson.toJson(returnvalue));
		out.flush(); 
	}

	private void processLongRefreshMatch(HttpServletRequest request,
			HttpServletResponse response) throws IOException, InterruptedException {

		String idMatch 	= request.getParameter("idmatch");
		String hash 	= request.getParameter("hash");
		ValueObjectMatch vom = null;
		boolean nothingHasChanged = true;
		long t= System.currentTimeMillis();
		long end = t+timer;
		do
		{
			vom = facadeGettersVo.getVOMatch(Integer.parseInt(idMatch));
			Gson gson = new Gson();
			if(!Md5.encode(gson.toJson(vom)).equals(hash))
			{
				nothingHasChanged = false;
				break;
			}
			else
			{
				Thread.sleep(3000);
			}
			if( System.currentTimeMillis() >= end)
			{
				break;
			}
		} while(nothingHasChanged);
		
		
		response.setContentType("application/json");
		PrintWriter out = response.getWriter();
		Gson gson = new Gson();
		String newhash = Md5.encode(gson.toJson(vom));
		Returnvalue returnvalue = new Returnvalue(newhash, vom);
		out.print(gson.toJson(returnvalue));
		out.flush();   	
	}
	
	

	protected void processInscriptionTournoi(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		String idtournoi = request.getParameter("idtournoi");
		HttpSession session = request.getSession(true);
		session.setAttribute("idTournoi", idtournoi);
		response.sendRedirect(SERVLET_INSCRIPTION);

	}


	protected void processPeupler(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		Peupler.creerArbitres(facadePeupler, 10);
		Peupler.creerTournoi(facadePeupler, 8);
		//Peupler.creerTournoi(facadePeupler, 2);
		//Peupler.creerTournoi(facadePeupler, 3);
		Peupler.creerTournoiEnCours(facadePeupler, 8);
		//Peupler.creerTournoiEnCoursTirAuBut(facadePeupler, 4);
		Peupler.creerTournoiTermine(facadePeupler, 16);
		this.processIndex(request, response);
	}

	protected void processRazBdd(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		this.facadePeupler.razBdd();
		this.processIndex(request, response);
	}

	protected void processIndex(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		HttpSession session = request.getSession(true);
		Collection<Tournoi> tournois = facadeGetters.getAllTournois();
		session.setAttribute(SA_TOURNOIS, tournois);
		Collection<ValueObjectEquipeDetail> equipes = facadeGettersVo.getVoAllEquipes();
		session.setAttribute(SA_EQUIPES, equipes);
		request.getRequestDispatcher(JSP_CONSULTATION).forward(request, response);
	}

	protected void processGetTournoiJSON(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, InterruptedException {
		String idTournoi = (String) request.getParameter("idtournoi");
		String hash = (String) request.getParameter("hash");		
		
		ValueObjectTournoi vot = null;
		boolean nothingHasChanged = true;
		long t= System.currentTimeMillis();
		long end = t+timer;
		do
		{
			vot = facadeGettersVo.getVoTournoi(Integer.valueOf(idTournoi));
			Gson gson = new Gson();
			if(!Md5.encode(gson.toJson(vot)).equals(hash))
			{
				nothingHasChanged = false;
				break;
			}
			else
			{
				Thread.sleep(3000);
			}
			if( System.currentTimeMillis() >= end)
			{
				break;
			}
		} while(nothingHasChanged);
		
		
		
		Map<Integer, List<ValueObjectMatch>> matchJSON = new HashMap<>();
		for(ValueObjectMatch match : vot.getMatchs())
		{
			int rang = match.getRangMatch();
			if(matchJSON.containsKey(rang))
			{
				matchJSON.get(rang).add(match);
			}
			else
			{
				matchJSON.put(Integer.valueOf(rang), new ArrayList<ValueObjectMatch>());
				matchJSON.get(rang).add(match);
			}
		}
	
		response.setContentType("application/json");
		PrintWriter out = response.getWriter();
		Gson gson = new Gson();
		String newhash = Md5.encode(gson.toJson(vot));
		Returnvalue returnvalue = new Returnvalue(newhash, matchJSON);
		out.print(gson.toJson(returnvalue));
		out.flush();  
	}

	protected void processDetailTournoi(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		HttpSession session = request.getSession(true);
		String idTournoi = (String) request.getParameter("idtournoi");
		ValueObjectTournoi vot = facadeGettersVo.getVoTournoi(Integer.valueOf(idTournoi));
		session.setAttribute(SA_VOTOURNOI, vot);

		Map<Integer, List<ValueObjectMatch>> matchJSON = new HashMap<>();
		for(ValueObjectMatch match : vot.getMatchs())
		{
			int rang = match.getRangMatch();
			if(matchJSON.containsKey(rang))
			{
				matchJSON.get(rang).add(match);
			}
			else
			{
				matchJSON.put(Integer.valueOf(rang), new ArrayList<ValueObjectMatch>());
				matchJSON.get(rang).add(match);
			}
		}
		Gson gson = new Gson();
		session.setAttribute(SA_VOTOURNOIHASH,  Md5.encode(gson.toJson(vot)));
		request.getRequestDispatcher(JSP_DETAIL_TOURNOI).forward(request, response);

	}

	protected void processDetailEquipe(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		HttpSession session = request.getSession(true);
		int idequipe = Integer.parseInt(request.getParameter("idequipe"));
		ValueObjectEquipeDetail equipes = facadeGettersVo.getVoEquipeDetail(idequipe);
		Collection<PosteJoueur> pj = facadeGetters.getPostesJoueurs();
		session.setAttribute(SA_POSTEJOUEUR, pj);
		session.setAttribute(SA_DETAIL_EQUIPE, equipes);
		request.getRequestDispatcher(JSP_DETAIL_EQUIPE).forward(request, response);
	}

	// <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
	/**
	 * Handles the HTTP <code>GET</code> method.
	 *
	 * @param request servlet request
	 * @param response servlet response
	 * @throws ServletException if a servlet-specific error occurs
	 * @throws IOException if an I/O error occurs
	 */
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		processRequest(request, response);
	}

	/**
	 * Handles the HTTP <code>POST</code> method.
	 *
	 * @param request servlet request
	 * @param response servlet response
	 * @throws ServletException if a servlet-specific error occurs
	 * @throws IOException if an I/O error occurs
	 */
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		processRequest(request, response);
	}

	/**
	 * Returns a short description of the servlet.
	 *
	 * @return a String containing servlet description
	 */
	@Override
	public String getServletInfo() {
		return "Servlet d'accueil pour utiliser l'application en mode non connecté";
	}// </editor-fold>

	
	private class Returnvalue
	{
		private String hashCode;
		private ValueObjectMatch vom;
		private Map<Integer, List<ValueObjectMatch>> vot;
		
		public Returnvalue(String hash, Map<Integer, List<ValueObjectMatch>> vot)
		{
			this.hashCode = hash;
			this.vot = vot;
		}
		
		public Returnvalue(String hash, ValueObjectMatch vom)
		{
			this.hashCode = hash;
			this.vom = vom;
		}

		public String getHashCode() {
			return hashCode;
		}

		public void setHashCode(String hashCode) {
			this.hashCode = hashCode;
		}

		public ValueObjectMatch getVom() {
			return vom;
		}

		public void setVom(ValueObjectMatch vom) {
			this.vom = vom;
		}
	}
}
